import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;

import XSD.*;

import Streams.XmlOutStream;
import XSD.BoardType;


public class TaW extends Thread {
	private int ID;
	private PositionType ownPos;
	private BoardType spielfeld;
	private XmlOutStream toServer;
	private ArrayList<MazeCom> moves;
	
	public TaW(int ID, BoardType spiel, Socket clientSocket){
		this.ID = ID;
		spielfeld = spiel;
		ownPos = getOwnPos();
		moves = new ArrayList<MazeCom>();
		try{
			toServer = new XmlOutStream(new DataOutputStream(clientSocket.getOutputStream()));
		}catch(IOException e){
			System.err.println("Ein Fehler beim Aufabu eines Streams zum Server ist in TaW-Construktor aufgetreten");
			System.exit(1);
		}
	}
	public void run(){
		moves.add(randomPlay());
		writeMoveToServer(0);
	}
	
	public void writeMoveToServer(int n){
		if(n>=moves.size()){
			toServer.write(randomPlay());
			return;
		}
		toServer.write(moves.get(n));
		
	}
	
	private MazeCom randomPlay(){
		MazeComMesFactory tmpFactory = new MazeComMesFactory();
		CardType shiftCard = spielfeld.getShiftCard();
		int shiftRow,shiftCol;
		shiftRow=0; shiftCol=1;
		int posRow = ownPos.getRow();
		int posCol = ownPos.getCol();
		int forbiddenRow = 0;
		int forbiddenCol = 0;
		if(spielfeld.getForbidden()!=null){
			forbiddenRow = spielfeld.getForbidden().getRow();
			forbiddenCol = spielfeld.getForbidden().getCol();
		}
		
		ObjectFactory myFac = new ObjectFactory();
		PositionType shiftPos = myFac.createPositionType();
		PositionType newOwnPos = myFac.createPositionType();
		boolean trie=true;
		while(trie){
			int rndNumber = (int) Math.round(Math.random()*11);
			//int rndNumber = 0;
			//Depending on the generated random number choose one of the predefined legal position to be shifted
			switch(rndNumber){
			case 0: shiftRow = 0; shiftCol=1; break;
			case 1: shiftRow = 0; shiftCol=3; break;
			case 2: shiftRow = 0; shiftCol=5;  break;
			case 3: shiftRow = 1; shiftCol=0;  break;
			case 4: shiftRow = 1; shiftCol=6;  break;
			case 5: shiftRow = 3; shiftCol=0;  break;
			case 6: shiftRow = 3; shiftCol=6;  break;
			case 7: shiftRow = 5; shiftCol=0;  break;
			case 8: shiftRow = 5; shiftCol=6;  break;
			case 9: shiftRow = 6; shiftCol=1;  break;
			case 10: shiftRow = 6; shiftCol=3;  break;
			default: shiftRow = 6; shiftCol=5; 
			}
			trie = false;
			if(forbiddenRow == shiftRow && forbiddenCol == shiftCol){
				trie=true;
			}
		}
		shiftPos.setRow(shiftRow);shiftPos.setCol(shiftCol);
		BoardType tmpSimulatedBoard = simulateNextStep(shiftPos, shiftCard);
		PositionType tmpSimulatedPosition = simulateNextPos(shiftPos, ownPos);
		posRow = tmpSimulatedPosition.getRow();
		posCol = tmpSimulatedPosition.getCol();
		ArrayList<PositionType> avaibPosList = new ArrayList<PositionType>();
		
			if(posRow > 0 && tmpSimulatedBoard.getRow().get(posRow).getCol().get(posCol).getOpenings().isTop() && tmpSimulatedBoard.getRow().get(posRow-1).getCol().get(posCol).getOpenings().isBottom()){
				PositionType myPos = myFac.createPositionType();
				myPos.setCol(posCol);
				myPos.setRow(posRow-1);
				avaibPosList.add(myPos);
			}if(posCol < 6 && tmpSimulatedBoard.getRow().get(posRow).getCol().get(posCol).getOpenings().isRight() && tmpSimulatedBoard.getRow().get(posRow).getCol().get(posCol+1).getOpenings().isLeft()){
				PositionType myPos = myFac.createPositionType();
				myPos.setCol(posCol+1);
				myPos.setRow(posRow);
				avaibPosList.add(myPos);
			} if(posRow < 6 && tmpSimulatedBoard.getRow().get(posRow).getCol().get(posCol).getOpenings().isBottom() && tmpSimulatedBoard.getRow().get(posRow+1).getCol().get(posCol).getOpenings().isTop()){
				PositionType myPos = myFac.createPositionType();
				myPos.setCol(posCol);
				myPos.setRow(posRow+1);
				avaibPosList.add(myPos);
			} if(posCol > 0 && tmpSimulatedBoard.getRow().get(posRow).getCol().get(posCol).getOpenings().isLeft() && tmpSimulatedBoard.getRow().get(posRow).getCol().get(posCol-1).getOpenings().isRight()){
				PositionType myPos = myFac.createPositionType();
				myPos.setCol(posCol-1);
				myPos.setRow(posRow);
				avaibPosList.add(myPos);
			}
		if(avaibPosList.size()==0)
			avaibPosList.add(tmpSimulatedPosition);
		int rndMove = (int)(Math.random()*avaibPosList.size());
		return tmpFactory.createMoveMessage(shiftPos, avaibPosList.get(rndMove), this.copyCard(shiftCard));
	}
	
	private PositionType getOwnPos(){
		ObjectFactory myFac = new ObjectFactory();
		PositionType myPos = myFac.createPositionType();
		for(int i=0;i<7;++i){
			for(int j=0;j<7;++j){
				if(spielfeld.getRow().get(i).getCol().get(j).getPin().getPlayerID().contains(ID)){
					myPos.setRow(i);
					myPos.setCol(j);
					return myPos;
				}
			}
		}
		return myPos;
	}
	
	private BoardType simulateNextStep(PositionType posShiftCard, CardType shiftCard){
		BoardType tmpBoard = copyBoard(spielfeld);
		int shiftRow = posShiftCard.getRow();
		int shiftCol = posShiftCard.getCol();
		if(shiftRow == 0 || shiftRow == 6){
			for(int i=1;i<7;++i){
				tmpBoard.getRow().get(Math.abs(shiftRow-i)).getCol().set(shiftCol, tmpBoard.getRow().get(Math.abs(shiftRow-i+1)).getCol().get(shiftCol));
			}
			
		}else if(shiftCol == 0 || shiftCol == 6){
			for(int i=1;i<7;++i){
				tmpBoard.getRow().get(shiftRow).getCol().set(Math.abs(shiftCol-i), tmpBoard.getRow().get(shiftRow).getCol().get(Math.abs(shiftCol-i+1)));
			}
		}
		tmpBoard.getRow().get(shiftRow).getCol().set(shiftCol,shiftCard);
		
		return tmpBoard;
	}
	private PositionType simulateNextPos(PositionType posShiftCard, PositionType ownPos){
		ObjectFactory myFac = new ObjectFactory();
		PositionType newOwnPos = myFac.createPositionType();
		newOwnPos.setRow(ownPos.getRow());
		newOwnPos.setCol(ownPos.getCol());
		if(posShiftCard.getCol() == ownPos.getCol()){
			if(posShiftCard.getRow() == 0){
				if(ownPos.getRow()==6){
					newOwnPos.setRow(0);
				}
				else{
					newOwnPos.setRow(ownPos.getRow()+1);
				}
			}
			else if(posShiftCard.getRow() == 6){
				if(ownPos.getRow()==0){
					newOwnPos.setRow(6);
				}
				else{
					newOwnPos.setRow(ownPos.getRow()-1);
				}
			}
		}
		else if(posShiftCard.getRow() == ownPos.getRow()){
			if(posShiftCard.getCol() == 0){
				if(ownPos.getCol()==6){
					newOwnPos.setCol(0);
				}
				else{
					newOwnPos.setCol(ownPos.getCol()+1);
				}
			}
			else if(posShiftCard.getCol() == 6){
				if(ownPos.getCol()==0){
					newOwnPos.setCol(6);
				}
				else{
					newOwnPos.setCol(ownPos.getCol()-1);
				}
			}
		}
		return newOwnPos;
		
	}
	
	private BoardType copyBoard(BoardType toBeCp){
		ObjectFactory myFac = new ObjectFactory();
		BoardType copyBoard = myFac.createBoardType();
		for(int i=0;i<7;++i){
			copyBoard.getRow().add(myFac.createBoardTypeRow());
			for(int j=0;j<7;++j){
				copyBoard.getRow().get(i).getCol().add(toBeCp.getRow().get(i).getCol().get(j));
			}
		}
		return copyBoard;
	}

	private CardType copyCard(CardType toBeCp){
		ObjectFactory myFac = new ObjectFactory();
		CardType copyCard = myFac.createCardType();
		CardType.Openings myOpenings = myFac.createCardTypeOpenings();
		myOpenings.setLeft(toBeCp.getOpenings().isLeft());
		myOpenings.setTop(toBeCp.getOpenings().isTop());
		myOpenings.setRight(toBeCp.getOpenings().isRight());
		myOpenings.setBottom(toBeCp.getOpenings().isBottom());
		copyCard.setOpenings(myOpenings);
		copyCard.setTreasure(toBeCp.getTreasure());
		copyCard.setPin(toBeCp.getPin());
		return copyCard;
		
	}
}
